#pragma once

#include <memory>
#include <string>
#include <chrono>
#include <thread>
#include <functional>

#include <sw/redis++/redis.h>
#include <json/json.h>

#include "logger.hpp"
#include "data_redis.hpp"

namespace suye
{
class CacheService
{
public:
    using ptr = std::shared_ptr<CacheService>;
    using DataFetcher = std::function<bool(const std::string& key, std::string& value)>;

    explicit CacheService(const std::shared_ptr<sw::redis::Redis>& redis_client,
                          std::chrono::seconds default_ttl = std::chrono::seconds(3600))
        : _redis_client(redis_client)
        , _default_ttl(default_ttl)
    {
        if (!_redis_client)
        {
            throw std::invalid_argument("CacheService requires valid Redis client");
        }
    }

    // Cache-Aside 模式：先查缓存，miss 时调用 fetcher 并回写
    bool get_with_fallback(const std::string& cache_key,
                           std::string& value,
                           const DataFetcher& fetcher,
                           const std::chrono::seconds& ttl = std::chrono::seconds(0))
    {
        try
        {
            auto cached = _redis_client->get(cache_key);
            if (cached)
            {
                value = *cached;
                LOG_DEBUG("CacheService 命中缓存: {}", cache_key);
                return true;
            }
        }
        catch (const std::exception& e)
        {
            LOG_WARN("CacheService 读取缓存失败: {} - {}", cache_key, e.what());
        }

        LOG_DEBUG("CacheService 缓存未命中: {}", cache_key);

        if (!fetcher)
        {
            return false;
        }

        std::string fetched_value;
        if (!fetcher(cache_key, fetched_value))
        {
            LOG_ERROR("CacheService fetcher 失败: {}", cache_key);
            return false;
        }

        value = fetched_value;

        try
        {
            const auto effective_ttl = (ttl.count() > 0) ? ttl : _default_ttl;
            _redis_client->set(cache_key, fetched_value, effective_ttl);
            LOG_DEBUG("CacheService 回写缓存成功: {}", cache_key);
        }
        catch (const std::exception& e)
        {
            LOG_WARN("CacheService 回写缓存失败: {} - {}", cache_key, e.what());
        }

        return true;
    }

    // 删除缓存
    bool invalidate(const std::string& cache_key)
    {
        try
        {
            _redis_client->del(cache_key);
            LOG_DEBUG("CacheService 删除缓存: {}", cache_key);
            return true;
        }
        catch (const std::exception& e)
        {
            LOG_ERROR("CacheService 删除缓存失败: {} - {}", cache_key, e.what());
            return false;
        }
    }

    // 延迟双删策略：先删缓存，等待业务更新 MySQL，延迟后再删一次
    void delayed_double_delete(const std::string& cache_key,
                              std::chrono::milliseconds delay = std::chrono::milliseconds(500))
    {
        invalidate(cache_key);

        if (delay.count() > 0)
        {
            std::thread([this, cache_key, delay]() {
                std::this_thread::sleep_for(delay);
                this->invalidate(cache_key);
                LOG_DEBUG("CacheService 延迟双删完成: {}", cache_key);
            }).detach();
        }
    }

    // 直接设置缓存
    bool set(const std::string& cache_key,
             const std::string& value,
             const std::chrono::seconds& ttl = std::chrono::seconds(0))
    {
        try
        {
            const auto effective_ttl = (ttl.count() > 0) ? ttl : _default_ttl;
            _redis_client->set(cache_key, value, effective_ttl);
            LOG_DEBUG("CacheService 设置缓存: {}", cache_key);
            return true;
        }
        catch (const std::exception& e)
        {
            LOG_ERROR("CacheService 设置缓存失败: {} - {}", cache_key, e.what());
            return false;
        }
    }

    // 批量删除（支持模式匹配）
    std::size_t invalidate_pattern(const std::string& pattern)
    {
        std::size_t deleted = 0;
        try
        {
            std::vector<std::string> keys;
            _redis_client->keys(pattern, std::back_inserter(keys));
            
            if (!keys.empty())
            {
                deleted = _redis_client->del(keys.begin(), keys.end());
                LOG_INFO("CacheService 批量删除缓存: pattern={}, count={}", pattern, deleted);
            }
        }
        catch (const std::exception& e)
        {
            LOG_ERROR("CacheService 批量删除缓存失败: {} - {}", pattern, e.what());
        }
        return deleted;
    }

private:
    std::shared_ptr<sw::redis::Redis> _redis_client;
    std::chrono::seconds _default_ttl;
};
}


